package com.learning.demos;

import java.util.concurrent.*;

/**
 * @author adolphw
 * 线程池的优势
 * 线程池的工作主要是控制运行的线程的数量，处理过程中将任务放入队列，然后在线程创建后启动这些任务，如果线程数量超过了最大数量，超出数量的线程排队
 * 等候，等其他线程执行完毕，再从队列中取出任务来执行。
 *
 * 主要特点：线程复用；控制最大并发数；管理线程
 *
 * 1 降低资源消耗，通过重复利用已创建的线程降低线程创建销毁造成的消耗
 * 2 提高响应速度，当任务到达时，任务可以不需要等到线程创建就能立即执行
 * 3 提高线程的可管理性，线程是稀缺资源，如果无限制创建，不仅会消耗系统资源，还会降低系统的稳定性，使用线程池可以进行统一的分配，调优和监控
 *
 * 大概5种线程池
 * Executors.newScheduledThreadPool()
 * Executors.newWorkStealingPool() java8 新特性
 *
 * Executors.newCachedThreadPool() 一池缓存不固定多线程 执行很多短期一步的小程序或者负载较轻的服务 Synch
 *     public static ExecutorService newCachedThreadPool() {
 *         return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
 *                                       60L, TimeUnit.SECONDS,
 *                                       new SynchronousQueue<Runnable>());
 *     }
 *
 * Executors.newFixedThreadPool() 一池固定数线程 执行长期任务，性能好很多
 *     public static ExecutorService newFixedThreadPool(int nThreads) {
 *         return new ThreadPoolExecutor(nThreads, nThreads,
 *                                       0L, TimeUnit.MILLISECONDS,
 *                                       new LinkedBlockingQueue<Runnable>());
 *     }
 *
 * Executors.newSingleThreadExecutor() 一池1线程 一个任务一个任务执行的场景
 *     public static ExecutorService newSingleThreadExecutor() {
 *         return new FinalizableDelegatedExecutorService
 *             (new ThreadPoolExecutor(1, 1,
 *                                     0L, TimeUnit.MILLISECONDS,
 *                                     new LinkedBlockingQueue<Runnable>()));
 *     }
 *
 * 底层 ThreadPoolExecutor Inspection '线程池不允许使用Executors去创建，而是通过ThreadPoolExecutor的方式，这样的处理方式让写的同学
 * 更加明确线程池的运行规则，规避资源耗尽的风险。' options
 *
 *     public ThreadPoolExecutor(int corePoolSize, 线程池中常驻的核心线程数
 *                               int maximumPoolSize, 线程池能够容纳同时执行的最大线程数，此值必须大于等于1
 *                               long keepAliveTime, 多余的空闲线程的存活时间；当前线程池数量超过corePoolSize时，多余的空闲线程会被
 *                               销毁直到只剩下corePoolSize个线程位置
 *                               TimeUnit unit, keepAliveTime的单位
 *                               BlockingQueue<Runnable> workQueue, 任务队列，被提交但尚未被执行的任务
 *                               ThreadFactory threadFactory, 表示生成线程池中工作线程的线程工厂，用于创建线程 一般默认的即可
 *                               RejectedExecutionHandler handler 拒绝策略，表示当队列满了冰鞋工作线程大雨等于线程池的最大线程数（maximumPoolSize）
 *
 *                               拒绝策略：
 *                               1 AbortPolicy(默认)：直接抛出RejectedExceptionException异常阻止系统正常运行
 *                               2 CallerRunsPolicy:"调用者运行"一种调节机制，该策略既不会抛弃任务，也不会抛出异常，而是将某些任务回退到调用者，从而降低新的任务流量
 *                               3 DiscardOldestPolicy:抛弃队列中等待最久的任务，然后把当前任务加入队列中尝试再次提交当前任务
 *                               4 DiskardPolicy:直接丢弃任务，不予任何处理也不抛出异常，如果允许任务丢失，这是最好的一种方案
 */
public class MyThreadPoolDemo {

    public static void main(String[] args) {
//        threadPoolInit();

        // 使用这种方式创建线程池
        // 如何合理的配置线程池

        System.out.println(Runtime.getRuntime().availableProcessors());
        /**
         * 线程池数量配置参考：
         * io密集型 ： 并不是一直在执行任务 即大量阻塞
         *  cpu核心数*2
         *
         *  参考公式： cpu核心数/1-阻塞系数     阻塞系数一般在0.8-0.9之间
         *
         *  比如8核心cpu  8/（1-0.9）=80个线程数
         *
         * cpu密集型
         * 一般是cpu核心数+1
         *
         */
        ExecutorService threadPool = new ThreadPoolExecutor(
                2,
                5,
                1L,
                TimeUnit.SECONDS,
                new LinkedBlockingDeque<Runnable>(3),
                Executors.defaultThreadFactory(),
                new ThreadPoolExecutor.DiscardPolicy());



        try {
            for (int i = 0; i < 50; i++) {
                threadPool.execute(()->{
                    System.out.println(Thread.currentThread().getName()+"\t 办理业务");
                });
            }

        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            threadPool.shutdown();
        }
    }

    private static void threadPoolInit() {
        System.out.println(Runtime.getRuntime().availableProcessors());

//        String aa = "db_12*";
//        System.out.println(aa.substring(3, aa.length()));

//        new Thread();
        // ThreadPoolExecutor

//         ExecutorService threadPool = Executors.newFixedThreadPool(5);
//         ExecutorService threadPool = Executors.newSingleThreadExecutor();
        ExecutorService threadPool = Executors.newCachedThreadPool();

//        new ThreadPoolExecutor(0, Integer.MAX_VALUE,
//                60L, TimeUnit.SECONDS,
//                new SynchronousQueue<Runnable>(),
//                threadFactory);

        // 模拟10个用户办理业务，每个用户就是一个来自外部的请求线程
        try {
            for (int i = 0; i < 20; i++) {
                threadPool.execute(()->{
                    System.out.println(Thread.currentThread().getName()+"\t 办理业务");
                });
            }

        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            threadPool.shutdown();
        }
    }
}
